package cn.lg.soar.system.auth.service;

import cn.lg.soar.common.util.current.UserContext;
import cn.lg.soar.common.util.data.DataUtil;
import cn.lg.soar.common.util.data.NumberUtil;
import cn.lg.soar.common.util.data.StringUtil;
import cn.lg.soar.common.util.lambda.LambdaUtils;
import cn.lg.soar.system.auth.entity.Org;
import cn.lg.soar.system.auth.entity.User;
import cn.lg.soar.system.auth.entity.UserOrg;
import cn.lg.soar.system.auth.model.UserSelectorDTO;
import cn.lg.soar.system.config.AuthCacheKey;
import cn.lg.soar.system.general.entity.UserTag;
import cn.lg.soar.system.general.entity.UserTagItem;
import cn.lg.soar.system.general.service.IUserTagService;
import cn.lg.soar.system.general.service.UserTagItemService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author luguoxiang
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
@RefreshScope
public class UserSelectorService {

    @Autowired
    private IUserService userService;
    @Autowired
    private IOrgService orgService;
    @Autowired
    private IUserTagService userTagService;
    @Autowired
    private UserOrgService userOrgService;
    @Autowired
    private UserTagItemService userTagItemService;

    public List<UserSelectorDTO> ids(Collection<Long> ids) {
        return userService.listByIds(ids, AuthCacheKey.USER_BY_ID)
                .stream()
                .map(UserSelectorDTO::from)
                .collect(Collectors.toList());
    }

    public List<UserSelectorDTO> query(String keyword) {
        return userService.page(
                new Page<>(1, 500),
                Wrappers.<User>lambdaQuery()
                        .select(User::getId, User::getAvatar, User::getUsername, User::getNickname)
                        .eq(User::getStatus, 0)
                        .nested(w -> w.like(User::getNickname, keyword)
                                .or()
                                .like(User::getUsername, keyword)
                        )
        ).getRecords()
                .stream()
                .map(UserSelectorDTO::from)
                .collect(Collectors.toList());
    }

    public List<UserSelectorDTO> org(Long parentId) {
        List<UserSelectorDTO> dtos;
        if(!Objects.equals(parentId, 0L)) {
            dtos = userService.list(
                            Wrappers.<User>lambdaQuery()
                                    .select(User::getId, User::getAvatar, User::getUsername, User::getNickname)
                                    .eq(User::getStatus, 0)
                                    .exists("select * from lg_sys_user_2_org o where lg_sys_user.id=o.user_id and o.org_id =" + parentId)

                    ).stream()
                    .map(UserSelectorDTO::from)
                    .collect(Collectors.toList());
        } else {
            dtos = new ArrayList<>(32);
        }
        List<Org> orgs = orgService.list(
                Wrappers.<Org>lambdaQuery()
                        .select(Org::getId, Org::getName, Org::getType, Org::getLeftNo, Org::getRightNo)
                        .eq(Org::getDisabled, false)
                        .eq(Org::getParentId, parentId)
        );
        if (!orgs.isEmpty()) {
            String idKey = StringUtil.camelToUnderscore(
                    LambdaUtils.getterToProperty(UserOrg::getOrgId)
            );
            Map<Long, Integer> map = userOrgService.listMaps(
                            Wrappers.<UserOrg>query()
                                    .select(idKey, "count(*) c")
                                    .in(idKey, orgs.stream().map(Org::getId).collect(Collectors.toList()))
                                    .groupBy(idKey)
                    ).stream()
                    .collect(Collectors.toMap(x -> DataUtil.toLong(x.get(idKey)), x -> DataUtil.toInteger(x.get("c"))));
            List<UserSelectorDTO> collect = orgs.stream()
                    .map(x -> {
                        UserSelectorDTO from = UserSelectorDTO.from(x);
                        from.setDescendantQuantity(NumberUtil.add(x.getDescendantQuantity(), map.get(x.getId())));
                        return from;
                    })
                    .collect(Collectors.toList());
            dtos.addAll(collect);
        }
        return dtos;
    }

    public List<UserSelectorDTO> tag(Long tagId) {
        if (tagId == null || Objects.equals(tagId, 0L)) {
            List<UserTag> tags = userTagService.list(
                    Wrappers.<UserTag>lambdaQuery()
                            .eq(UserTag::getUserId, UserContext.getUserId())
            );
            if (!tags.isEmpty()) {
                String idKey = StringUtil.camelToUnderscore(
                        LambdaUtils.getterToProperty(UserTagItem::getTagId)
                );
                Map<Long, Integer> map = userTagItemService.listMaps(
                                Wrappers.<UserTagItem>query()
                                        .select(idKey, "count(*) c")
                                        .in(idKey, tags.stream().map(UserTag::getId).collect(Collectors.toList()))
                                        .groupBy(idKey)
                        ).stream()
                        .collect(Collectors.toMap(x -> DataUtil.toLong(x.get(idKey)), x -> DataUtil.toInteger(x.get("c"))));
                return tags.stream()
                        .map(x -> {
                            UserSelectorDTO from = UserSelectorDTO.from(x);
                            from.setDescendantQuantity(map.get(x.getId()));
                            return from;
                        })
                        .collect(Collectors.toList());
            }
        }

        return userService.list(
                        Wrappers.<User>lambdaQuery()
                                .select(User::getId, User::getAvatar, User::getUsername, User::getNickname)
                                .eq(User::getStatus, 0)
                                .exists("select * from lg_sys_user_2_tag o where lg_sys_user.id=o.user_id and o.tag_id =" + tagId)

                ).stream()
                .map(UserSelectorDTO::from)
                .collect(Collectors.toList());
    }

}
